from typing import Dict, Union, Tuple, List

from assets.constant import SPECIAL_ENCHANT_MAP
from base.attribute import Attribute
from base.buff import Buff
from base.gain import Gain
from base.recipe import DamageAdditionRecipe
from base.skill import Skill
from general.buffs.equipment import BUFFS
from general.skills.equipment import SKILLS


class EquipmentGain(Gain):
    buff_ids: List[int] = None
    skill_ids: List[int] = None
    attributes: Dict[str, List[int]] = {}
    rate: Union[int, float] = 1
    level: int = 0
    real_formulation: bool = True

    def __init__(self, level=0):
        super().__init__()
        self.level = level

    def add_buffs(self, buffs: Dict[int, Buff]):
        if self.buff_ids and self.real_formulation:
            for buff_id in self.buff_ids:
                buffs[buff_id].activate = True

    def sub_buffs(self, buffs: Dict[int, Buff]):
        if self.buff_ids and self.real_formulation:
            for buff_id in self.buff_ids:
                buffs[buff_id].activate = False

    def add_skills(self, skills: Dict[int, Skill]):
        if self.skill_ids:
            for skill_id in self.skill_ids:
                skills[skill_id].activate = True

    def sub_skills(self, skills: Dict[int, Skill]):
        if self.skill_ids:
            for skill_id in self.skill_ids:
                skills[skill_id].activate = False

    def add_attribute(self, attribute: Attribute):
        if (self.skill_ids or self.buff_ids) and self.real_formulation:
            return
        for attr, values in self.attributes.items():
            setattr(attribute, attr, getattr(attribute, attr) + int(values[self.level - 1] * self.rate))

    def sub_attribute(self, attribute: Attribute):
        if (self.skill_ids or self.buff_ids) and self.real_formulation:
            return
        for attr, values in self.attributes.items():
            setattr(attribute, attr, getattr(attribute, attr) - int(values[self.level - 1] * self.rate))


class CriticalSet(EquipmentGain):
    rate = 0.7

    def __init__(self, buff_id, buff):
        self.buff_ids = [buff_id]
        self.attributes = buff.attributes
        buff.activate = False
        super().__init__()


class DivineEffect(EquipmentGain):
    skill_ids = []

    def __init__(self, skill_id):
        super().__init__()
        self.skill_ids = [skill_id]


class DivineSubSkill(EquipmentGain):
    skill_ids = []

    def __init__(self, skill_id):
        super().__init__()
        self.skill_ids = [skill_id]


class WaterWeapon(EquipmentGain):
    buff_ids = [4761]
    attributes = BUFFS[4761].attributes
    rate = 10


class WindPendant(EquipmentGain):
    buff_ids = [6360]
    attributes = BUFFS[6360].attributes
    rate = 15 / 180


class 大附魔帽(EquipmentGain):
    # buff_ids = [15436]
    attributes = BUFFS[15436].attributes


class 大附魔衣(EquipmentGain):
    attributes = dict(
        physical_attack_power_base=SKILLS[22151].physical_attack_power_base,
        magical_attack_power_base=SKILLS[22151].magical_attack_power_base
    )


class 大附魔腰(EquipmentGain):
    buff_ids = [15455]
    attributes = {
        attr: [sum(value * prob for value, prob in zip(values, [0.3, 0.7]))]
        for attr, values in BUFFS[15455].attributes.items()
    }
    rate = 8 / 30


class 大附魔腕(EquipmentGain):
    skill_ids = list(range(22160, 22164 + 1)) + [37562]


class 大附魔鞋(EquipmentGain):
    skill_ids = list(range(33257, 33261 + 1)) + [37561]


def set_real_formulation(tag):
    EquipmentGain.real_formulation = tag


def set_critical_set_rate(rate):
    CriticalSet.rate = rate


EQUIPMENT_GAINS: Dict[Union[Tuple[int, int], int], Gain] = {
    **{
        (k,): WaterWeapon(i)
        for k, i in {
            2400: 55, 2401: 56,
            2497: 59, 2498: 60,
            2539: 63, 2540: 64,
            2604: 67, 2605: 68
        }.items()
    },
    **{
        (6800, i + 1): WindPendant(i + 1)
        for i in range(BUFFS[6360].max_level)
    },
    **{
        (15436, i + 1): 大附魔帽(i + 1)
        for i in range(BUFFS[15436].max_level)
    },
    **{
        (22151, i + 1): 大附魔衣(i + 1)
        for i in range(13)
    },
    **{
        tuple(gain): 大附魔腰()
        for gain in SPECIAL_ENCHANT_MAP[6].values()
    },
    **{
        tuple(gain): 大附魔腕()
        for gain in SPECIAL_ENCHANT_MAP[10].values()
    },
    **{
        tuple(gain): 大附魔鞋()
        for gain in SPECIAL_ENCHANT_MAP[9].values()
    },

    17250: DamageAdditionRecipe(55, 0, 0, 4),
    17239: DamageAdditionRecipe(21, 0, 0, 4),
}
